<?php

namespace App\Traits;

use App\Models\Permission;
use App\Models\Role;

trait HasPermissions
{
    public function getAllPermissions()
    {
        $permissions = $this->permissions;
        foreach ($this->roles as $role) {
            $permissions = $permissions->merge($role->permissions);
        }
        return $permissions;
    }

    public function givePermissionsTo(...$permissions)
    {
        $permissions = $this->getPermissions($permissions);
        if ($permissions === null) {
            return $this;
        }
        $this->permissions()->saveMany($permissions);
        return $this;
    }

    public function withdrawPermissionsTo(...$permissions)
    {
        $permissions = $this->getPermissions($permissions);
        $this->permissions()->detach($permissions);
        return $this;
    }

    public function refreshPermissions(...$permissions)
    {
        $this->permissions()->detach();
        return $this->givePermissionsTo($permissions);
    }

    /**
     * @param Permission|string $permission
     *
     * @return bool
     */
    public function hasPermissionTo($permission)
    {
        $permission = $this->resolveToPermission($permission);

        if (!$permission) {
            return false;
        }

        return $this->hasPermissionThroughRole($permission) || $this->hasPermission($permission);
    }

    /**
     * @param $permission
     *
     * @return bool
     */
    public function hasPermissionThroughRole($permission)
    {
        $permission = $this->resolveToPermission($permission);

        if (!$permission) {
            return false;
        }

        return $permission->roles()->pluck('id')->intersect($this->roles()->pluck('id'))->isNotEmpty();
    }

    public function hasRole(...$roles)
    {
        foreach ($roles as $role) {
            if ($this->roles->contains('slug', $role)) {
                return true;
            }
        }
        return false;
    }

    public function assignRole(...$roles)
    {
        $roles = Role::whereIn('slug', $roles)->get();

        if ($roles === null) {
            return $this;
        }

        $this->roles()->attach($roles);
        return $this;
    }

    public function removeRole(...$roles)
    {
        $roles = Role::whereIn('slug', $roles)->get();
        $this->roles()->detach($roles);
        return $this;
    }

    public function syncRoles(...$roles)
    {
        $roles = Role::whereIn('slug', $roles)->get();
        $this->roles()->detach($roles);
        return $this;
    }

    public function isSuperAdmin()
    {
        return $this->hasRole('super-admin');
    }

    public function roles()
    {
        return $this->belongsToMany(Role::class, 'users_roles');
    }

    public function permissions()
    {
        return $this->belongsToMany(Permission::class, 'users_permissions');
    }

    /**
     * @param Permission|string $permission
     *
     * @return boolean
     */
    protected function hasPermission($permission)
    {
        if ($permission instanceof Permission) {
            $permission = $permission->slug;
        }

        return $this->permissions()->where('slug', $permission)->exists();
    }

    /**
     * @param array $permissions
     *
     * @return \Illuminate\Database\Eloquent\Collection
     */
    protected function getPermissions(array $permissions)
    {
        return Permission::whereIn('slug', $permissions)->get();
    }

    /**
     * @param $permission
     *
     * @return Permission
     */
    protected function resolveToPermission($permission)
    {
        if ($permission instanceof Permission) {
            return $permission;
        }

        return Permission::where('slug', $permission)->first();
    }
}
